#ifndef MEPA_H_
#define MEPA_H_

/**
 * Todos os comandos da mepa sao implementados nesta Classe.
 * 
 * Detalhes do arquivo de entrada, uso dos construtores e
 * saidas serao descritos durante codigo.
 * 
 * Materia de Compiladores, UEL 2007
 * Alunos:
 * 			Doulgas andre Schmidt
 * 			Fernando Biesdorf 
 */

#include <string>
#include <vector>
#include <fstream>
#include <iostream>

using namespace std;

/* Struct usada para compor P[] */
struct LinhaMepa
{
	std::string instrucao;
	std::vector<int> args;
};

struct Label
{
	char
	label[6];
	
	int linha;
};

class Mepa
{	
private:
			/**
			 * O nome do arquivo com codigo fonte em Mepa
			 * será passado por parametro na linha de comando
			 * Este aquivo sera de nome [*].mep
			 */	
			std::fstream
			pontoMep;
			
			/* Nome do arquivo de entrada */
			const char* pontoMepString;
		   
		    /**
		     * Arquivo que contera a saida do DUMP de memoria
		     * caso o parametro <nome do arquivo saida> seja
		     * passado ao comando -MM do compilador
		     */
		    std::ofstream
		    dumpOut;
		    
		    /* Nome do arquivo de saida */
		    const char* dumpOutString;
	
	/*##### Inicio do Corpo Principal da Mepa #####*/
	
			/**
			 * Vector de strings que representa o programa
			 */
			std::vector<struct LinhaMepa>
			P;
			
			/**
			 * Vector M de int que representa a
			 * memoria de dados
			 */
			std::vector<int>
			M;
			
			/**
			 * A memoria eh indexado por s
			 */
			int
			s;
			
			/**
			 * Vector que contem as bases, ponteiros
			 * para posicoes na memoria M
			 */
			std::vector<int>
			D;
			
			/**
			 * i aponta para a para a proxima
			 * instrucao, no vector P
			 */
			int
			i;
	
	/*##### Fim do Corpo Principal da Mepa #####*/
	

	
	
	
	
	/*===================================*/
	
	
	
	
	

	/*##### Inicio dos Comandos da Mepa #####*/
	
	
	
			/* === Comandos de Carregamento === */
			
					/**
					 * Carregar constante
					 * 
					 * @param int k, carrega constante k para a memoria
					 */
					void crct(int k);
					
					/**
					 * Carrega valor
					 * 
					 * M[s] := M[D[k] + n]
					 * 
					 * @param int k, indexador de D
					 * @param int n, deslocamento base D[k] sobre indexacao em M
					 */
					void crvl(int k, int n);
			
			
			
			/* === Comandos matematicos === */
			
					/**
					 * Soma
					 * 
					 * em M, dois pop's, soma eles, e entao push o resultado
					 */
					void soma();
					
					/**
					 * Subtrai
					 * 
					 * em M, dois pop's, subtrai eles, e entao push o resultado
					 */
					void subt();
					
					/**
					 * Multiplica
					 * 
					 * em M, dois pop's, os mulplica, e entao push o resultado
					 */
					void mult();
					
					/**
					 * Divisao inteira
					 * 
					 * em M, dois pop's, os divide(resto escoria), e entao push o resultado
					 */
					void divi();
					
					/**
					 * Inverte sinal
					 * 
					 * em M, um pop, inverte o sinal, e push o resultado
					 */
					void invr();
			
			
			
			/* === Comandos de Logicos === */
			
					/**
					 * Conjuncao
					 * 
					 * se ( M[s-1]=1 E M[s]=1 ) entao
				     * 	M[s-1] :=1
				     * senao
				     *		M[s-1] := 0
					 *	s := s – 1
					 */
					void conj();
					
					/**
					 * Disjuncao
					 * 
					 *  se ( M[s-1]=1 OU M[s]=1 ) entao
				     * 	M[s-1] :=1
				     * senao
				     *		M[s-1] := 0
					 *	s := s – 1
					 */
					void disj();
					
					/**
					 * Negacao
					 * 
					 * M[s] := 1 – M[s]
					 */
					void nega();	
			
			
			
			/* === Comandos Relacionais === */
			
					/**
					 * Compara menor
					 * 
					 * em M, se pop2 < pop1, push 1, verdadeiro
					 */
					void cmme();
					
					/**
					 * Compara maior
					 * 
					 * em M, se pop2 > pop1, push 1, verdadeiro
					 */
					void cmma();
					
					/**
					 * Compara igual
					 * 
					 * em M, se pop2 == pop1, push 1, verdadeiro
					 */
					void cmig();
					
					/**
					 * Compara desigual
					 * 
					 * em M, se pop2 != pop1, push 1, verdadeiro
					 */
					void cmdg();
					
					/**
					 * Compara menor igual
					 * 
					 * em M, se pop2 <= pop1, push 1, verdadeiro
					 */
					void cmeg();
					
					/**
					 * Compara maior igual
					 * 
					 * em M, se pop2 >= pop1, push 1, verdadeiro
					 */
					 void cmag();
			 
			 
			 
			 /* === Comando de Atribuicao === */
			 
					 /**
					  * Armazena valor
					  * 
					  * Armazena valor de M[s] em M[D[k] + n]
					  * 
					  * @param int k, indice de D
					  * @param int n, deslocamento base D[k] sobre M
					  */
					 void armz(int k, int n);
			 
			 
			 
			 /* === Comandos Condicionais e Iterativos === */
			 
					 /**
					  * Desvia sempre
					  * 
					  * @param int p, indice em P, destino do desvio
					  */
					 void dsvs(int p);
					 
					 /**
					  * Desvia se falso
					  * 
					  * Apenas desvia se M[s] == 0
					  * 
					  * @param int p, indice em P, destino do desvio
					  */
					 void dsvf(int p);
					 
					 /**
					  * Nada
					  */
					 void nada();
			 
			 
			 
			 /* === Comandos de Entrada e Saida === */
			 
					 /**
					  * Leitura
					  */
					 void leit();
					 
					 /**
					  * Imprimir
					  * 
					  * Imprime de M[s]
					  */
					 void impr();
					 
					 /**
					  * Imprimir e pular linha
					  * 
					  * *Comando nao original de Mepa
					  */
					 void impl();
					 
					 /**
					  * Imprimir caractere e pula linha
					  * 
					  * *Comando nao original da Mepa
					  */
					 void impc();
			 
			 
			 
			 /* === Comandos de Programa === */
			 
					 /**
					  * Inicia Programa Principal
					  */
					 void inpp();
					 
					 /**
					  * Alocar memoria
					  * 
					  * @param int m, numero de palavras a alocar
					  */
					 void amem(int m);
					 
					 /**
					  * Desalocar memoria
					  * 
					  * @param int n, numero de palavras a desalocar
					  */
					 void dmem(int n);
					 
					 /**
					  * Para
					  * 
					  * Para a execucao da Mepa
					  */
					 void para();
			 
			 
			 
			 /* === Comandos para Procedimentos sem parametros === */
			 
					 /**
					  * Chama procedimento
					  * 
					  * Chama o procedimento pelo rotulo deste, label.
					  * Aqui o Program Counter, o i, eh levado a linha do do rotulo
					  * mas essa linha deve conter o Comando Mepa = NADA
					  * Então a proxima instrucao sempre será a de ENPR, veja adiante...
					  * 
					  * @param int l, o rotulo
					  */
					 void chpr(int l);
					 
					 /**
					  * Entrar no procedimento
					  * 
					  * Primeiro comando logo apos entra em qualquer procedimento,
					  * onde k eh o nivel lexico deste. Este comando muda o nivel
					  * lexico atual.
					  * 
					  * @param int k, nivel de procedimento que acaba-se de entrar
					  */
					 void enpr(int k);
					 
					 /**
					  * Retornar do Procedimento
					  * 
					  * Marca o fim de um procedimento, atualizando o nivel
					  * lexico do Program Counter, o i.
					  * 
					  * @param int k, nivel léxico do procedimento que esta sendo deixado
					  * @param int n, sei lah
					  */
					 void rtpr(int k, int n);
			 
			 
			 
			 /* === Comandos para Procedimentos com Parametros por Referencia === */
			 
					 /**
					  * Carrega Valor Indiretamente
					  * 
					  * M[s] := M[ M[D[k] + n] ]
					  * 
					  * @param int k, indice em D
					  * @param int n, deslocamento em M com base em D[k]
					  */
					 void crvi(int k, int n);
					 
					 /**
					  * Armazena Valor Indiretamente
					  * 
					  * M[ M[D[k]+n] ] := M[s]
					  * 
					  * @param int k, indice em D
					  * @param int n, deslocamento em M com base em D[k]
					  */
					 void armi(int k, int n);
					 
					 /**
					  * Carrega Endereco
					  * 
					  * Carrega um endereco de D[k]+n em M[s]
					  * 
					  * @param int k, indice em D
					  * @param int n, deslocamento em D com base em D[k]
					  */
					 void cren(int k, int n);
					 
					 /**
					  * Mostrar memoria
					  * 
					  * *Nao e um comando original da Mepa.
					  * 
					  * Dump de memória
					  */
					 void mosm();	 
		
	/*##### Fim dos Comandos da Mepa #####*/
					 
	/* Gambis pra ler os dois tipos de arquivos diferentes */
		std::vector<struct Label>
		labels;
		
	/* Gambis pra makina parar ou nao... */
		bool continuar;
	 
	 
	 
public:
			
	
	/* Operacoes sobre o i, Program Counter */
			void setI(int novoI);
			void incrementaI();
	
	/* Construtores e destrutor */
			Mepa();																/* Construtor simples */
			Mepa(const char*, int, int, int );							/* Construtor sem arquivo de dump */
			Mepa(const char*, const char*, int, int, int);		/* Construtor com arquivo de dump */
			virtual ~Mepa();													/* Limpa a sujeira e fecha a Mepa */
		
	/* Comandos externos */
			void carregaPrograma();									/* Carrega pontoMep em P[] */
			void rodar();														/* Executa P[] */ 
	
	
	
};

#endif /*MEPA_H_*/
